//------------------------------------------------------------------------------
//  Effect.cpp
//  (C) 2009 xoyojank
//------------------------------------------------------------------------------
#include "StdEddy.h"
#include "Graphics/Effect.h"

//------------------------------------------------------------------------------
namespace Eddy
{

const EffectId EffectId::InvalidId(0, 0);

//------------------------------------------------------------------------------
Effect::Effect()
    : program(0)
    , isBegin(false)
{
    // empty
}

//------------------------------------------------------------------------------
Effect::~Effect()
{
    assert(!this->isBegin);

    this->variableMap.clear();

    glDeleteProgram(this->program);
}

//------------------------------------------------------------------------------
void
Effect::Begin()
{
    assert(!this->isBegin);
    assert(glIsProgram(this->program));

    // active
    glUseProgram(this->program);

    // commit uniforms
    GLint texIndex = -1;
    for (EffectVariableMap::iterator it = this->variableMap.begin();
            it != this->variableMap.end(); ++it)
    {
        const EffectVariablePtr& variable = it->second;
        if (EffectVariable::TextureType == variable->type)
            ++texIndex;
        variable->Commit(texIndex);
    }

    this->isBegin = true;
}

//------------------------------------------------------------------------------
void
Effect::End()
{
    assert(this->isBegin);

    this->isBegin = false;
}

//------------------------------------------------------------------------------
void
Effect::InitUniformMap()
{
    assert(glIsProgram(this->program));

    GLint numUniforms = 0;
    glGetProgramiv(this->program, GL_ACTIVE_UNIFORMS, &numUniforms);

    char name[32];
    GLint size;
    GLenum type;
    for (IndexT i = 0; i < SizeT(numUniforms); ++i)
    {
        glGetActiveUniform(this->program, i, 32, NULL, &size, &type, name);
        EffectVariablePtr variable = new EffectVariable();
        variable->name = name;
        variable->SetType(type);
        variable->location = glGetUniformLocation(this->program, name);

        this->variableMap[variable->name] = variable;
    }
}

//------------------------------------------------------------------------------
const EffectVariablePtr&
Effect::GetVariable(const String& name)
{
    EffectVariableMap::iterator it = this->variableMap.find(name);
    if (this->variableMap.end() == it)
    {
        assert(false);
        static const EffectVariablePtr nullPtr;
        return nullPtr;
    }
    else
    {
        return it->second;
    }
}

}// Eddy
